#!/usr/bin/env python
"""
:mod:`pynchon.bio.io.jalview`
=============================

Provides read/write support for the jalview annotations and features.
"""
from collections import defaultdict
from random import randint
from pynchon.plot.color import NAMED_COLORS
from pynchon.bio.io.fasta import _get_id_comment
 
SEQUENCE_GROUP_RNG = 'SEQUENCE_GROUP\t%s\t%s\t%s\t%s-%s\n'
SEQUENCE_GROUP_IDS = 'SEQUENCE_GROUP\t%s\t%s\t%s\t%s\t%s\n'
COLOUR = 'COLOUR\t%s\t%s\n'
BAR_GRAPH = 'BAR_GRAPH\t%s\t%s\n'
BAR_GRAPH_FIELD = "%.2f,%c[%s]"
LINE_GRAPH = 'LINE_GRAPH\t%s\t%s\n'
LINE_GRAPH_FIELD = "%.2f"
BAR_GRAPH_FIELD = "%.2f,%c[%s]"
PROPERTIES = "PROPERTIES\t%s\t%s\n"
DEFAULT_PROPERTIES = "PROPERTIES\t%s\toutlineColour=000000\tdisplayBoxes=true\tdisplayText=true\tcolourText=false\tidColour=%s\n"

def write_annotations_groups(fh, array, key ='SEQUENCE_GROUP', properties =None):
    """
    Creates a Jalview annotations file from a ``SymbolArray`` or a sequence of 
    ``SymbolVectors``, the groups are created based on the value corresponding
    to the given key. The key should be the beginning of a comments line.
    
    Arguments:
    
        - fh (``file``) An open for writing file handle.
        - array (``SymbolArray``) A ``SymbolArray`` instance or sequence of 
          ``SymbolVectors``with valid comments lines. A valid comment line is of
          the form "KEY:IDENTIFIER"
        - key (``str``) The key from a comment line.
        - properties (``dict``) A mapping between every "IDENTIFIER" and a valid
          "PROPERTIES" line in the Jalview annotation file format.
    """
    length = max([len(seq) for seq in array])
    colors = NAMED_COLORS.values()
    fh.write('JALVIEW_ANNOTATION\n')
    id_val = _get_id_comment(array, key)
    group_ids = defaultdict(list)
    for id, val in id_val:
        group_ids[val].append(id)
    for group, ids in group_ids.iteritems():
        fh.write(SEQUENCE_GROUP_IDS % (group, 1, length, -1, "\t".join(ids)))
        if properties:
            fh.write(PROPERTIES % (group, properties[group]))
        else:
            fh.write(DEFAULT_PROPERTIES % (group, colors.pop(randint(0, len(colors)-1))))
        fh.write('\n')
        
        
def write_annotations_graphs(fh, array, key, type='BAR_GRAPH'):
    """
    Creates a Jalview annotations file with sequence feature graphs e.g. bar 
    charts from a ``SymbolArray`` with proper metadata. A ``sequence`` of tuples
    valid for the given "type" of the graph should be stored in the "metadata"
    dictionary of the ``SymbolArray`` and/or its "entities" for the specified
    "key". The ``SymbolArray`` can define the default colour of the graph under
    the "$key$_COLOUR", where "$KEY$" is the "key" argument. The entities within
    the ``SymbolArray`` will be groups in the annotation file and can define the
    following keys: "$key$_COLOUR" - a group specific color of the graph, "name"
    - an arbitrary group name, "GROUP_PROPERTIES" - a string of group properties
    valid for the Jalview annotations file format.:
    
         - LINE_GRAPH - (number,) e.g ``(11.,)``
         - BAR_GRAPH - (number,char,color) e.g. ``(2,'A','green')``
     
    Arguments:
    
        - fh (``file``) An open for writing file handle.
        - array (``SymbolArray``) A ``SymbolArray`` instance with feature 
          vectors in the "metadata" attribute or entities with such vectors.
        - key (``str``) A key to find the feature vector in the "metadata" 
          attribute of the ``SymbolArray``.
        - type (``str``) [default: ``BAR_GRAPH``] The other options are 
          "LINE_GRAPH"
    """
    line = eval(type)
    field = eval(type + '_FIELD')
    colors = NAMED_COLORS.values()
    fh.write('JALVIEW_ANNOTATION\n')
    # groups
    first = 1
    for id, group in enumerate(array.entities):
        last = first + len(group)
        group_data = group.metadata.get(key, None)
        if group_data:
            group_colr = group.metadata.get(key + '_COLOUR', None)
            group_name = group.metadata.get('name', "GROUP_%s" % id)
            group_prps = group.metadata.get('GROUP_PROPERTIES', None)
            group_key = key + '_' + group_name
            group_vals = "|".join([field % data for data in group_data])
            # define group
            fh.write(SEQUENCE_GROUP_RNG % (group_name, 1, array.shape[-1], first, last))
            # start group block
            fh.write('SEQUENCE_REF\t%s\n' % group_name)
            # write graph
            fh.write(line % (group_key, group_vals))
            # change graph color
            if group_colr:
                fh.write(COLOUR % (key + '_' + group_name, group_colr))
            # change group properties
            if group_prps:
                fh.write(PROPERTIES % (group_name, group_prps))
            else:
                fh.write(DEFAULT_PROPERTIES % (group_name, (group_colr or colors.pop(randint(0, len(colors)-1)))))
        first = last + 1
    # alignment
    alignment_data = array.metadata.get(key, None)
    if alignment_data:
        alignment_colr = array.metadata.get(key + '_COLOUR', None)
        alignment_vals = "|".join([field % data for data in alignment_data])
        fh.write('SEQUENCE_REF\tALIGNMENT\n')
        fh.write(line % (key, alignment_vals))
        if alignment_colr:
            fh.write(COLOUR % (key, alignment_colr))

def write_features():
    """
    """
    pass
    
